import { InjectRepository } from '@nestjs/typeorm';
import {
  WebSocketGateway,
  SubscribeMessage,
  MessageBody,
  ConnectedSocket,
  WebSocketServer,
  OnGatewayConnection,
  OnGatewayDisconnect,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import Chat from 'src/entities/chat.entity';
import { Repository } from 'typeorm';
import { AddFriendDto, FriendMessageDto } from './chat.dto';
import Friend from 'src/entities/friend.entity';
import { isEmpty } from 'lodash';
import { ApiException } from 'src/core/exceptions/api.exception';
import User from 'src/entities/user.entity';
import Delivery from 'src/entities/delivery.entity';
import Apply from 'src/entities/apply.entity';

@WebSocketGateway()
export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
  constructor(
    @InjectRepository(Chat) private chatRepository: Repository<Chat>,
    @InjectRepository(Friend) private friendRepository: Repository<Friend>,
    @InjectRepository(User) private userRepository: Repository<User>,
    @InjectRepository(Delivery) private deliveryRepository: Repository<Delivery>,
    @InjectRepository(Apply) private applyRepository: Repository<Apply>,
  ) {}

  @WebSocketServer()
  server: Server;

  // 连接
  handleConnection(client: Socket, ...args: any[]) {
    const userRoom = client.handshake.query.userId;
    if (userRoom) {
      client.join(userRoom);
    }
    return '连接成功';
  }

  // 添加好友
  @SubscribeMessage('addFriend')
  async addFriend(@MessageBody() data: AddFriendDto, @ConnectedSocket() client: Socket) {
    const { userId, friendId } = data;

    if (userId && friendId) {
      if (userId === friendId) {
        this.server.to(userId).emit('addFriend', { code: 201, message: '不能添加自己为好友' });
        return;
      }

      // 查询是否已经是好友
      const relation1 = await this.friendRepository.findOne({ where: { userId, friendId } });
      const relation2 = await this.friendRepository.findOne({
        where: { userId: friendId, friendId: userId },
      });

      // 已有好友
      if (relation1 || relation2) {
        this.server.to(userId).emit('addFriend', { code: 201, message: '已经有该好友' });
        return;
      } else {
        // 添加好友
        await this.friendRepository.save({ userId, friendId });
        await this.friendRepository.save({ userId: friendId, friendId: userId });
        this.server.to(data.userId).emit('addFriend', { code: 200, message: '添加好友成功' });
      }
    }
  }

  // 加入私聊
  @SubscribeMessage('joinFriendSocket')
  async joinFriend(@MessageBody() data: FriendMessageDto, @ConnectedSocket() client: Socket) {
    const { userId, friendId } = data;
    if (userId === friendId) {
      throw new ApiException(15001);
    }

    const relation = await this.friendRepository.findOne({ where: { userId, friendId } });
    const roomId = userId > friendId ? userId + friendId : friendId + userId;

    if (relation) {
      client.join(roomId);
      this.server
        .to(userId)
        .emit('joinFriendSocket', { code: 200, msg: '进入私聊socket成功', data: relation });
    }
  }

  // 发送私聊消息
  @SubscribeMessage('friendMessage')
  async friendMessage(@MessageBody() data: FriendMessageDto, @ConnectedSocket() client: Socket) {
    const { userId, friendId } = data;

    if (userId && friendId) {
      await this.chatRepository.save(data);
      const roomId = userId > friendId ? userId + friendId : friendId + userId;
      this.server.to(roomId).emit('friendMessage', { code: 200, message: '', data });
    }
  }

  // 系统通知
  // TODO 后面可以建立一张系统通知表
  @SubscribeMessage('notice')
  async noticeMessage(@MessageBody() data: FriendMessageDto, @ConnectedSocket() client: Socket) {
    const { userId, friendId } = data;

    if (userId && friendId) {
      this.server.to(userId).emit('notice', { code: 200, message: '系统通知', data });
    }
  }

  // 投递简历
  @SubscribeMessage('delivery')
  async deliveryResume(@MessageBody() data: any, @ConnectedSocket() client: Socket) {
    const { userId, friendId, info } = data;

    if (userId && friendId) {
      this.server.to(friendId).emit('delivery', { code: 200, message: '系统通知', data: info });
    }
  }

    // 面试预约
    @SubscribeMessage('apply')
    async interviewApply(@MessageBody() data: any, @ConnectedSocket() client: Socket) {
      const { userId, friendId, info } = data;
  
      if (userId && friendId) {
        this.server.to(friendId).emit('apply', { code: 200, message: '系统通知', data: info });
      }
    }

  // 获取聊天信息
  @SubscribeMessage('chatData')
  async allChatData(@MessageBody() data, @ConnectedSocket() client: Socket) {
    const userId = client.handshake.query.userId as string;
    // 获取好友列表
    const friendList = await this.friendRepository.find({ where: { userId } });
    // 获取投递简历列表
    const deliveryList = await this.deliveryRepository.find({ where: { friendId: userId } });
    // 获取面试邀请列表
    const applyList = await this.applyRepository.find({ where: { friendId: userId } });

    // 处理好友和聊天信息
    const friendPromises = friendList.map(async (item) => {
      // 获取好友信息
      const friend = await this.userRepository.findOne({
        where: { id: item.friendId },
        select: ['avatar', 'nickname'],
      });

      // 获取和好友的聊天信息
      const messages = await this.chatRepository
        .createQueryBuilder('chat')
        .orderBy('chat.created_at', 'ASC')
        .where(
          '(chat.userId = :userId AND chat.friendId = :friendId) OR (chat.userId = :friendId AND chat.friendId = :userId)',
          {
            userId: item.userId,
            friendId: item.friendId,
          },
        )
        .take(30)
        .getMany();
      return { ...friend, userId, friendId: item.friendId, messages };
    });

    const friends = await Promise.all(friendPromises);

    this.server.to(userId).emit('chatData', {
      code: 200,
      message: '获取聊天信息成功',
      data: {
        friends,
        noticeList: [...deliveryList, ...applyList],
      },
    });
  }

  // 断开连接
  handleDisconnect(client: Socket) {
    console.log(`Client disconnected: ${client.id}`);
  }
}
